package wator.model.agents;

import java.util.HashMap;
import java.util.Map;

import wator.model.Agent;
import wator.model.DrawingStrategy;
import wator.model.IntegerVector;
import wator.model.MovementStrategy;
import wator.model.Neighborhood;
import wator.model.NoDrawingStrategy;
import wator.model.strategies.NoMovementStrategy;

/**
 * This is an extended version of the original shark implementation, in which
 * the sharks are associated with a certain energy level. If they eat a fish,
 * their energy raises according to its size. Zero energy sharks die. Breeding
 * splits the parent's energy among the parent and the child.
 */
public class EnergySharkAgent extends Agent {
	
	private static int startEnergy = 10;
	private static int breedEnergy = 30;

	
	private static MovementStrategy movementStrategy = 
			new NoMovementStrategy();
	private static DrawingStrategy drawingStrategy = 
			new NoDrawingStrategy();
	private int energy = startEnergy;
	private int lastFishRound = 0;

	/**
	 * This constructor creates a shark agent and takes the position and
	 * direction vectors from another agent instance.
	 *  
	 * @param agent the agent from which position and direction vectors
	 * 			are taken (not copied)
	 */
	public EnergySharkAgent(Agent agent) {
		super(agent);
	}
	
	/**
	 * Sharks always eat fishes in their reach, but only one per round.
	 * {@inheritDoc}
	 */
	@Override
	public boolean eats(Neighborhood.Neighbor prey) {
		if (lastFishRound > 0 && prey.getAgent() instanceof FishAgent) {
			lastFishRound = 0;
			energy += prey.getAgent().getEnergy();
			return true;
		}
		return false;
	}
	
	/**
	 * All fishes are on the menu.
	 * {@inheritDoc}
	 */
	@Override
	public boolean isOnMenu(Agent prey) {
		return (prey instanceof FishAgent);
	}

	/**
	 * Sharks move according their movement strategy, so this functionality
	 * is directly delegated to the current strategy instance. They loose
	 * energy in each round.
	 * {@inheritDoc}
	 * @see #setMovementStrategy(MovementStrategy) 
	 */
	@Override
	public IntegerVector move(Neighborhood neighborhood) {
		energy--;
		lastFishRound++;
		return movementStrategy.apply(this, neighborhood);
	}

	/**
	 * Sharks breed as soon as their energy is above breedEnergy. Only one
	 * individual is necessary for breeding. The energy of the parent is split
	 * among parent and child.
	 * 
	 * @param neighborhood The neighborhood of the parent (not used)
	 * @return a new agent if the breedEnergy is reached, null otherwise
	 */
	@Override
	public Agent breed(Neighborhood neighborhood) {
		if (energy >= breedEnergy) {
			energy /= 2;
			EnergySharkAgent child = new EnergySharkAgent(this);
			child.energy = energy;
			return child;
		}
		return null;
	}

	/**
	 * Sharks starve if their energy level is zero.
	 * 
	 * @param neighborhood The neighborhood of the parent (not used)
	 * @return <code>true</code> if this shark starves, <code>false</code> 
	 * 		otherwise
	 */
	@Override
	public boolean dies(Neighborhood neighborhood) {
		return energy <= 0;
	}
	
	/**
	 * Parameters of this species are startEnergy and breedEnergy.
	 * {@inheritDoc}
	 */
	@Override
	public void setSpeciesParameter(String key, int value) {
		if (key.equals("Start Energy")) {
			startEnergy = value;
		} else if (key.equals("Breed Energy")) {
			breedEnergy = value;
		}
	}

	/**
	 * Parameters of this species are startEnergy and breedEnergy.
	 * {@inheritDoc}
	 */
	@Override
	public Map<String, Integer> getSpeciesParameters() {
		HashMap<String, Integer> params = new HashMap<String, Integer>();
		params.put("Start Energy", startEnergy);
		params.put("Breed Energy", breedEnergy);
		return params;
	}

	/* (non-Javadoc)
	 * @see wator.model.Agent#getMovementStrategy()
	 */
	@Override
	public MovementStrategy getMovementStrategy() {
		return movementStrategy;
	}

	/* (non-Javadoc)
	 * @see wator.model.Agent#setMovementStrategy(wator.model.MovementStrategy)
	 */
	@Override
	public void setMovementStrategy(MovementStrategy strategy) {
		movementStrategy = strategy;
	}
	
	/* (non-Javadoc)
	 * @see wator.model.Agent#setDrawingStrategy(wator.model.DrawingStrategy)
	 */
	@Override
	public void setDrawingStrategy(DrawingStrategy strategy) {
		drawingStrategy = strategy;
	}

	/* (non-Javadoc)
	 * @see wator.model.Agent#draw()
	 */
	@Override
	public void draw() {
		drawingStrategy.draw(this);
	}
	
	/* (non-Javadoc)
	 * @see wator.model.Agent#clone()
	 */
	@Override
	protected Object clone() {
		return new EnergySharkAgent(this);
	}
	
	/* (non-Javadoc)
	 * @see wator.model.Agent#getSpeciesName()
	 */
	@Override
	public String getSpeciesName() {
		return "Energy driven Shark";
	}
}
